using System;
using System.Collections.Generic;
using System.Linq;

namespace MT5Trade.Models.MarketData
{
    /// <summary>
    /// 市场状态检测器
    /// 用于识别市场是否处于高频震荡状态
    /// </summary>
    public class MarketRegimeDetector
    {
        #region 常量定义

        // ADX阈值
        private const double ADX_TREND_THRESHOLD = 25.0;  // ADX < 25表示无明显趋势
        private const double ADX_STRONG_TREND = 40.0;     // ADX > 40表示强趋势

        // RSI震荡区间
        private const double RSI_LOWER_BOUND = 40.0;
        private const double RSI_UPPER_BOUND = 60.0;

        // 布林带参数
        private const int BB_PERIOD = 20;
        private const double BB_STD_DEV = 2.0;

        // 震荡频率阈值
        private const int MIN_OSCILLATIONS_FOR_RANGING = 3;  // 最少震荡次数
        private const double OSCILLATION_TIME_WINDOW = 60.0; // 时间窗口（分钟）

        #endregion

        #region 市场状态枚举

        public enum MarketRegime
        {
            /// <summary>
            /// 强趋势市场
            /// </summary>
            StrongTrend,

            /// <summary>
            /// 弱趋势市场
            /// </summary>
            WeakTrend,

            /// <summary>
            /// 高频震荡市场
            /// </summary>
            HighFrequencyOscillation,

            /// <summary>
            /// 低波动横盘
            /// </summary>
            LowVolatilityRanging,

            /// <summary>
            /// 未知/过渡状态
            /// </summary>
            Unknown
        }

        #endregion

        #region 私有字段

        private readonly Queue<MarketSnapshot> _priceHistory;
        private readonly int _historySize;
        private DateTime _lastUpdateTime;

        #endregion

        #region 构造函数

        public MarketRegimeDetector(int historySize = 100)
        {
            _historySize = historySize;
            _priceHistory = new Queue<MarketSnapshot>(historySize);
            _lastUpdateTime = DateTime.MinValue;
        }

        #endregion

        #region 核心检测方法

        /// <summary>
        /// 检测当前市场状态
        /// </summary>
        /// <param name="marketData">市场数据</param>
        /// <returns>市场状态结果</returns>
        public MarketRegimeResult DetectMarketRegime(SimpleMarketData marketData)
        {
            // 更新价格历史
            UpdatePriceHistory(marketData);

            // 如果历史数据不足，返回未知状态
            if (_priceHistory.Count < 30)
            {
                return new MarketRegimeResult
                {
                    Regime = MarketRegime.Unknown,
                    Confidence = 0.0,
                    Message = "历史数据不足"
                };
            }

            // 计算各项指标
            var adxValue = CalculateADX();
            var rsiValue = CalculateRSI();
            var bbPosition = CalculateBollingerBandPosition(marketData.CurrentPrice);
            var oscillationFreq = CalculateOscillationFrequency();
            var priceRange = CalculatePriceRange();

            // 综合判断市场状态
            return DetermineMarketRegime(
                adxValue,
                rsiValue,
                bbPosition,
                oscillationFreq,
                priceRange,
                marketData.Volatility);
        }

        /// <summary>
        /// 判断是否为高频震荡市场
        /// </summary>
        public bool IsHighFrequencyOscillation(SimpleMarketData marketData)
        {
            var result = DetectMarketRegime(marketData);
            return result.Regime == MarketRegime.HighFrequencyOscillation;
        }

        /// <summary>
        /// 计算预期胜率（用于震荡市场）
        /// </summary>
        public double CalculateWinProbability(MarketRegimeResult regimeResult)
        {
            switch (regimeResult.Regime)
            {
                case MarketRegime.StrongTrend:
                    return 0.65; // 趋势市场胜率较高

                case MarketRegime.WeakTrend:
                    return 0.55; // 弱趋势略高于50%

                case MarketRegime.HighFrequencyOscillation:
                    return 0.50; // 震荡市场胜率约50%

                case MarketRegime.LowVolatilityRanging:
                    return 0.52; // 低波动略高于50%

                default:
                    return 0.50; // 默认50%
            }
        }

        #endregion

        #region 技术指标计算

        /// <summary>
        /// 计算ADX（平均趋向指数）
        /// </summary>
        private double CalculateADX()
        {
            if (_priceHistory.Count < 14)
                return 0;

            var prices = _priceHistory.ToArray();
            double[] plusDM = new double[prices.Length - 1];
            double[] minusDM = new double[prices.Length - 1];
            double[] trueRange = new double[prices.Length - 1];

            // 计算方向运动和真实范围
            for (int i = 1; i < prices.Length; i++)
            {
                var current = prices[i];
                var previous = prices[i - 1];

                double highDiff = current.High - previous.High;
                double lowDiff = previous.Low - current.Low;

                plusDM[i - 1] = highDiff > lowDiff && highDiff > 0 ? highDiff : 0;
                minusDM[i - 1] = lowDiff > highDiff && lowDiff > 0 ? lowDiff : 0;

                trueRange[i - 1] = Math.Max(
                    current.High - current.Low,
                    Math.Max(
                        Math.Abs(current.High - previous.Close),
                        Math.Abs(current.Low - previous.Close)
                    )
                );
            }

            // 计算平滑移动平均
            double atr = trueRange.Take(14).Average();
            double plusDI = plusDM.Take(14).Average() / atr * 100;
            double minusDI = minusDM.Take(14).Average() / atr * 100;

            // 计算ADX
            double dx = Math.Abs(plusDI - minusDI) / (plusDI + minusDI) * 100;
            return dx;
        }

        /// <summary>
        /// 计算RSI（相对强弱指数）
        /// </summary>
        private double CalculateRSI(int period = 14)
        {
            if (_priceHistory.Count < period + 1)
                return 50; // 返回中性值

            var prices = _priceHistory.Select(p => p.Close).ToArray();
            double gains = 0;
            double losses = 0;

            for (int i = 1; i <= period; i++)
            {
                double change = prices[prices.Length - i] - prices[prices.Length - i - 1];
                if (change > 0)
                    gains += change;
                else
                    losses -= change;
            }

            double avgGain = gains / period;
            double avgLoss = losses / period;

            if (avgLoss == 0)
                return 100;

            double rs = avgGain / avgLoss;
            double rsi = 100 - (100 / (1 + rs));

            return rsi;
        }

        /// <summary>
        /// 计算布林带位置
        /// </summary>
        private BollingerBandPosition CalculateBollingerBandPosition(double currentPrice)
        {
            if (_priceHistory.Count < BB_PERIOD)
                return new BollingerBandPosition { Position = 0.5, Width = 0 };

            var recentPrices = _priceHistory.Skip(Math.Max(0, _priceHistory.Count - BB_PERIOD))
                                           .Select(p => p.Close)
                                           .ToArray();

            double sma = recentPrices.Average();
            double variance = recentPrices.Select(p => Math.Pow(p - sma, 2)).Average();
            double stdDev = Math.Sqrt(variance);

            double upperBand = sma + (BB_STD_DEV * stdDev);
            double lowerBand = sma - (BB_STD_DEV * stdDev);
            double bandWidth = upperBand - lowerBand;

            // 计算当前价格在布林带中的相对位置（0-1）
            double position = 0.5;
            if (bandWidth > 0)
            {
                position = (currentPrice - lowerBand) / bandWidth;
                position = Math.Max(0, Math.Min(1, position));
            }

            return new BollingerBandPosition
            {
                UpperBand = upperBand,
                MiddleBand = sma,
                LowerBand = lowerBand,
                Position = position,
                Width = bandWidth
            };
        }

        /// <summary>
        /// 计算震荡频率
        /// </summary>
        private double CalculateOscillationFrequency()
        {
            if (_priceHistory.Count < 10)
                return 0;

            var prices = _priceHistory.Select(p => p.Close).ToArray();
            int crossings = 0;
            double sma = prices.Average();

            // 计算价格穿越均线的次数
            for (int i = 1; i < prices.Length; i++)
            {
                if ((prices[i - 1] < sma && prices[i] > sma) ||
                    (prices[i - 1] > sma && prices[i] < sma))
                {
                    crossings++;
                }
            }

            // 计算时间跨度（分钟）
            var timeSpan = (_priceHistory.Last().Timestamp - _priceHistory.First().Timestamp).TotalMinutes;
            if (timeSpan <= 0) timeSpan = 1;

            // 返回每小时的穿越次数
            return (crossings / timeSpan) * 60;
        }

        /// <summary>
        /// 计算价格区间
        /// </summary>
        private double CalculatePriceRange()
        {
            if (_priceHistory.Count < 2)
                return 0;

            var prices = _priceHistory.Select(p => p.Close).ToArray();
            double highest = prices.Max();
            double lowest = prices.Min();
            double average = prices.Average();

            if (average == 0)
                return 0;

            // 返回相对价格区间（百分比）
            return (highest - lowest) / average * 100;
        }

        #endregion

        #region 辅助方法

        /// <summary>
        /// 更新价格历史
        /// </summary>
        private void UpdatePriceHistory(SimpleMarketData marketData)
        {
            var snapshot = new MarketSnapshot
            {
                Open = marketData.CurrentOpen,
                High = marketData.CurrentHigh,
                Low = marketData.CurrentLow,
                Close = marketData.CurrentPrice,
                Volume = marketData.CurrentVolume,
                Timestamp = marketData.Timestamp
            };

            _priceHistory.Enqueue(snapshot);

            if (_priceHistory.Count > _historySize)
            {
                _priceHistory.Dequeue();
            }

            _lastUpdateTime = marketData.Timestamp;
        }

        /// <summary>
        /// 综合判断市场状态
        /// </summary>
        private MarketRegimeResult DetermineMarketRegime(
            double adx,
            double rsi,
            BollingerBandPosition bbPos,
            double oscillationFreq,
            double priceRange,
            double volatility)
        {
            var result = new MarketRegimeResult();

            // 强趋势判断
            if (adx > ADX_STRONG_TREND)
            {
                result.Regime = MarketRegime.StrongTrend;
                result.Confidence = Math.Min(adx / 50.0, 1.0);
                result.Message = $"强趋势市场 (ADX={adx:F1})";
            }
            // 高频震荡判断
            else if (adx < ADX_TREND_THRESHOLD &&
                    rsi >= RSI_LOWER_BOUND && rsi <= RSI_UPPER_BOUND &&
                    oscillationFreq > MIN_OSCILLATIONS_FOR_RANGING)
            {
                result.Regime = MarketRegime.HighFrequencyOscillation;
                result.Confidence = CalculateOscillationConfidence(adx, rsi, oscillationFreq);
                result.Message = $"高频震荡市场 (震荡频率={oscillationFreq:F1}/小时)";

                // 设置震荡市场的附加信息
                result.OscillationMetrics = new OscillationMetrics
                {
                    Frequency = oscillationFreq,
                    PriceRange = priceRange,
                    ADX = adx,
                    RSI = rsi,
                    EstimatedWinRate = 0.5 // 震荡市场胜率约50%
                };
            }
            // 弱趋势判断
            else if (adx >= ADX_TREND_THRESHOLD && adx <= ADX_STRONG_TREND)
            {
                result.Regime = MarketRegime.WeakTrend;
                result.Confidence = 0.6;
                result.Message = $"弱趋势市场 (ADX={adx:F1})";
            }
            // 低波动横盘
            else if (priceRange < 1.0 && volatility < 0.1)
            {
                result.Regime = MarketRegime.LowVolatilityRanging;
                result.Confidence = 0.7;
                result.Message = "低波动横盘市场";
            }
            else
            {
                result.Regime = MarketRegime.Unknown;
                result.Confidence = 0.3;
                result.Message = "市场状态不明确";
            }

            return result;
        }

        /// <summary>
        /// 计算震荡市场置信度
        /// </summary>
        private double CalculateOscillationConfidence(double adx, double rsi, double oscillationFreq)
        {
            double adxScore = Math.Max(0, (ADX_TREND_THRESHOLD - adx) / ADX_TREND_THRESHOLD);
            double rsiScore = 1.0 - Math.Abs(rsi - 50) / 50.0; // RSI越接近50分数越高
            double freqScore = Math.Min(oscillationFreq / 10.0, 1.0); // 频率越高分数越高

            // 加权平均
            return (adxScore * 0.4 + rsiScore * 0.3 + freqScore * 0.3);
        }

        #endregion
    }

    #region 数据结构定义

    /// <summary>
    /// 市场快照
    /// </summary>
    public class MarketSnapshot
    {
        public double Open { get; set; }
        public double High { get; set; }
        public double Low { get; set; }
        public double Close { get; set; }
        public double Volume { get; set; }
        public DateTime Timestamp { get; set; }
    }

    /// <summary>
    /// 布林带位置
    /// </summary>
    public class BollingerBandPosition
    {
        public double UpperBand { get; set; }
        public double MiddleBand { get; set; }
        public double LowerBand { get; set; }
        public double Position { get; set; } // 0-1之间，表示相对位置
        public double Width { get; set; }    // 带宽
    }

    /// <summary>
    /// 市场状态检测结果
    /// </summary>
    public class MarketRegimeResult
    {
        public MarketRegimeDetector.MarketRegime Regime { get; set; }
        public double Confidence { get; set; } // 0-1之间的置信度
        public string Message { get; set; }
        public OscillationMetrics OscillationMetrics { get; set; }
    }

    /// <summary>
    /// 震荡市场指标
    /// </summary>
    public class OscillationMetrics
    {
        public double Frequency { get; set; }      // 震荡频率
        public double PriceRange { get; set; }     // 价格区间
        public double ADX { get; set; }            // ADX值
        public double RSI { get; set; }            // RSI值
        public double EstimatedWinRate { get; set; } // 预估胜率
    }

    #endregion
}